type Maybe [out T] enum {
    type Some weak T;
    type None;
};

export function Some:
    [T] &(T) => Maybe[T]
    &(t) => { |Maybe| { |Some| t } };

export const None: Maybe[never]
    { |Maybe| { |None[never]| () } };

export method Maybe.Bool: Bool
    &(v?) =>
        switch v?:
        case Some _:
            Yes,
        case None:
            No,
        end;

export function map:[A,B]
    &(Maybe[A], &(A) => B) => Maybe[B]
    &(v?, f) =>
        switch v?:
        case Some v:
            { Some { f v } },
        case None:
            None,
        end;

export function Maybe:[A,B]
    &(Maybe[A], &(A) => Maybe[B]) => Maybe[B]
    &(v?, k) =>
        switch v?:
        case Some v:
            { k v },
        case None:
            None,
        end;

export function Maybe:[A,B,T]
    &((Maybe[A],Maybe[B]), &(A,B) => T) => Maybe[T]
    &(pair, f) =>
        let (a?, b?) := pair,
        \ Maybe let a := a?,
        \ Maybe let b := b?,
        { Some { f(a,b) } };

export function Maybe:[A,B,C,T]
    &((Maybe[A],Maybe[B],Maybe[C]), &(A,B,C) => T) => Maybe[T]
    &(triple, f) =>
        let (a?, b?, c?) := triple,
        \ Maybe let a := a?,
        \ Maybe let b := b?,
        \ Maybe let c := c?,
        { Some { f(a,b,c) } };

export function continue:[A,T]
    &({ if-some: Maybe[A], otherwise: T }, &(A) => T) => T
    &(arg, f) =>
        let {if-some,otherwise} := arg,
        switch if-some:
        case Some v:
            { f(v) },
        case None:
            otherwise,
        end;

export function ??:[T]
    &(Maybe[T], T) => T
    &(t?, fallback) =>
        switch t?:
        case Some t:
            t,
        case None:
            fallback,
        end;


